/*
 * @Author: yangzonglong
 * @Date: 2021-02-25 14:35:43
 * @version: v1.0.0
 * @Descripttion:
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-07-28 15:14:21
 * @Auditor:
 */
import React, { useCallback, useState, useEffect, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';
import Table from './../table/Table';
import Modal from './../modal/Modal';
import { Skeleton } from 'antd';
import { ModalTableInModelProps, ModelProps } from './interface';
import { getModelApi } from './api';
import { bodyStyle, defaultModel, DEFAULT_WIDTH, DEFAULT_ROWSELECTIONTYPE } from './data';
import Search from './../search/Search';
import styles from './styles.module.scss';
import Formx from './../formx/Formx';
import { FormxRefProps } from './../formx/interface';
import { TableRefProps } from './../table/interface';

export default forwardRef(
  ({
    url,
    visible,
    onCancel,
    onOk,
    model,
    rowSelectionType,
    syncModel,
    moduleName,
    fieldNames,
    modelName,
    width,
    pageModelCode,
    query: baseQuery,
    hideSearch,
    showSelected,
    defaultSelected,
    handleQuerySet,
    handleResult,
    treeStructure,
    treeId,
    treeParentId,
    showAutoSearch // 为true时 将自动搜索，用于低代码 搜索几个字符不需要手动回车
  }: ModalTableInModelProps, ref: any) => {
    const isInitModel = useRef(false);

    const tableRef = useRef<TableRefProps>(null);
    const formRef = useRef<FormxRefProps>(null);
    const selectRowKeys = useRef<any>({});

    const [curModel, setCurModel] = useState<ModelProps>(defaultModel);
    const cacheDefaultSelected = useRef<any[]>([]);
    const [selected, setSelected] = useState<any[]>([]);
    const [searchQuery, setSearchQuery] = useState({});
    const [loading, setLoading] = useState(false);
    const searchChangeTimer = useRef<any>(null);

    const handleQuery = useMemo(() => {
      return { ...searchQuery, ...baseQuery, ...curModel.query };
    }, [searchQuery, curModel.query, baseQuery]);

    useImperativeHandle(ref, () => ({
      getSearchQuery: (value: string, fuzzyField: string[]) => {
        const fuzzy = {
          fuzzyField,
          fuzzyQuery: true,
          fuzzyValue: value,
          pages: {
            page: 1,
            pageSize: 50
          }
        };
        const mergeQuery = { ...fuzzy, ...baseQuery, ...curModel.query };
        return handleQuerySet ? handleQuerySet(mergeQuery) : mergeQuery;
      }
    }));

    useEffect(() => {
      if (isInitModel.current) return;

      if (model) {
        syncModel?.(model);
        return setCurModel(model);
      }
      setLoading(true);
      getModelApi(moduleName!, modelName!, pageModelCode).then((model) => {
        model.query = baseQuery;
        if (url) model.url = url;
        setCurModel(model);
        syncModel?.({
          ...model,
          fieldNames: model.fieldNames || fieldNames,
        });
        setLoading(false);
        isInitModel.current = true;
      });
    }, [moduleName, modelName, model, syncModel, fieldNames, pageModelCode, baseQuery, url]);

    useEffect(() => {
      if (defaultSelected !== cacheDefaultSelected.current && defaultSelected) {
        setSelected(defaultSelected);
        cacheDefaultSelected.current = defaultSelected;
      }
    }, [defaultSelected]);

    const _onCancel = useCallback(() => {
      onCancel?.();
      setSearchQuery({});
    }, [onCancel]);

    const _onOk = useCallback(() => {
      const rows = tableRef.current?.getSelectedRows();
      onOk?.((rowSelectionType === 'checkbox' ? selected : rows) || []);
      setSearchQuery({});
    }, [onOk, selected, rowSelectionType]);

    function onSearch(fuzzyValue: string) {
      if (showSelected) {
        selectRowKeys.current = tableRef?.current?.getSelectRow();
      }
      if (!fuzzyValue) return setSearchQuery({});
      setSearchQuery({ fuzzyField: curModel.searchFields, fuzzyQuery: true, fuzzyValue });
    }

    const placeholder = useMemo(() => {
      const join = curModel.searchFieldsText?.map((item) => window.$app.t(item)).join('/');
      return window.$app.t('pleaseEnter') + join;
    }, [curModel.searchFieldsText]);

    const advancedSearch = useCallback(async () => {
      const data = await formRef.current?.validateFields();
      const obj = {};
      for (const key in data) {
        if (Object.prototype.hasOwnProperty.call(data, key)) {
          const element = data[key];
          if (element !== null && key.indexOf('_') !== 0) obj[key] = element;
        }
      }
      setSearchQuery({ where: obj });
    }, []);

    const advancedReset = useCallback(() => {
      formRef.current?.resetFields();
      setSearchQuery({ where: {} });
    }, []);

    const fullToggle = () => {
      tableRef.current?.resetScroll?.();
    };

    const suffixForm = useMemo(() => {
      return curModel.advancedSearchFormItems && <Formx ref={formRef} groupNumber={1} formItems={curModel.advancedSearchFormItems || []} />;
    }, [curModel.advancedSearchFormItems]);

    const rowSelectionChange = useCallback((rowKeys: string[], rows: any[], itemRowKey, curPageSelectedKeys) => {
      if (rowSelectionType === 'checkbox') {
        selectRowKeys.current = {};

        // 单条选中 / 取消
        if (itemRowKey) {
          if (Object.values(itemRowKey)[0]) {
            const row = rows.find(item => item.id === Object.keys(itemRowKey)[0]);
            setSelected(prev => {
              cacheDefaultSelected.current = prev.concat(row);
              return cacheDefaultSelected.current;
            });
          } else {
            setSelected(prev => {
              cacheDefaultSelected.current = prev.filter(item => item.id !== Object.keys(itemRowKey)[0]);
              return cacheDefaultSelected.current;
            });
          }
        } else { // 全选反选
          const rows = tableRef.current?.getDataSource();

          if (curPageSelectedKeys.length) {
            setSelected(prev => {
              const newSelected = prev.concat(rows);
              const newSelectedMap = newSelected.reduce((next, cur) => {
                next[cur.id] = cur;
                return next;
              }, {});

              cacheDefaultSelected.current = Object.values(newSelectedMap);
              return cacheDefaultSelected.current;
            });
          } else {
            const rowsMap = rows?.reduce((next, cur) => {
              next[cur.id] = true;
              return next;
            }, {});

            setSelected(prev => {
              cacheDefaultSelected.current = prev.filter(item => !rowsMap[item.id]);
              return cacheDefaultSelected.current;
            });
          }
        }
      } else {
        const thisSelectedRows = rows.filter(item => rowKeys.includes(item.id)); // 表格所有选中行
        setSelected(thisSelectedRows.concat(cacheDefaultSelected.current));
      }
    }, [rowSelectionType]);

    const remove = (id: string) => {
      tableRef.current?.removeSelectedRowKeys([id]);
      const newSelected = selected.filter(item => item.id !== id);
      setSelected(newSelected);
      cacheDefaultSelected.current = cacheDefaultSelected.current.filter(item => item.id !== id);
    };

    const getId = (array: any[], resultRowKeyMaps: {} = {}) => {
      array.forEach(item => {
        resultRowKeyMaps[item.id] = true;
        if (treeStructure && item.children) {
          getId(item.children, resultRowKeyMaps);
        }
      });

      return resultRowKeyMaps;
    };

    const _handleResult = (result: any) => {
      // const resultRowKeyMaps = result.rows?.reduce((next: any, cur: any) => {
      //   next[cur.id] = true;
      //   return next;
      // }, {});
      const resultRowKeyMaps = getId(result.rows);
      const pageSelected = cacheDefaultSelected.current.filter(item => resultRowKeyMaps[item.id]);

      if (pageSelected?.length) {
        tableRef.current?.setSelectRowKeys(
          pageSelected.map(item => item.id),
          pageSelected
        );
      }

      return handleResult?.(result);
    };

    const searchChange = (e: any) => {
      const value = e.target.value || '';

      if (searchChangeTimer.current) {
        clearTimeout(searchChangeTimer.current);
        searchChangeTimer.current = null;
      }

      searchChangeTimer.current = setTimeout(() => {
        if (value.length >= 3) onSearch(value);
      }, 500);
    };

    return (
      <Modal
        showFullIcon
        destroyOnClose
        title={curModel.title}
        bodyStyle={bodyStyle}
        width={showSelected ? 1000 : (width || DEFAULT_WIDTH)}
        onCancel={_onCancel}
        onOk={_onOk}
        visible={visible}
        fullToggle={fullToggle}
      >
        <Skeleton active loading={loading}>
          {
            showSelected ? <div className={styles.main}>
              <div className={styles.waiting}>
                {!hideSearch && (
                  <div className={styles.search}>
                    <Search
                      advancedReset={advancedReset}
                      advancedSearch={advancedSearch}
                      suffix={suffixForm}
                      onSearch={onSearch}
                      placeholder={placeholder}
                      onChange={showAutoSearch ? searchChange : undefined}
                    />
                  </div>
                )}
                <Table
                  query={handleQuerySet ? handleQuerySet(handleQuery) : handleQuery}
                  rowSelectionType={rowSelectionType || DEFAULT_ROWSELECTIONTYPE}
                  rowSelectionChange={rowSelectionChange}
                  ref={tableRef}
                  columns={curModel.columns}
                  url={curModel.url}
                  handleResult={_handleResult}
                  treeStructure={treeStructure}
                  treeId={treeId}
                  treeParentId={treeParentId}
                />
              </div>
              {rowSelectionType === 'checkbox' && (
                <div className={styles.sidebar}>
                  <h2>{window.$app.t('selected')}{curModel.title}<span>({selected.length})</span></h2>
                  <ul>
                    {selected.map(item => (
                      <li key={item.id}>
                        <span style={{
                          display: 'block',
                          width: '130px',
                          overflow: 'hidden',
                          textOverflow: 'ellipsis',
                          whiteSpace: 'nowrap'

                        }}>{Array.isArray(showSelected) ? showSelected.reduce((all: string, now: any, index: number) => {
                          return all + item[now.value] + (index === showSelected.length - 1 ? '' : '-');
                        }, '') : item?.[showSelected]}</span>
                        <span onClick={() => remove(item.id)} className={styles.delAction}>{window.$app.t('delete')}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
            </div> : <>
              {!hideSearch && (
                <div className={styles.search}>
                  <Search
                    advancedReset={advancedReset}
                    advancedSearch={advancedSearch}
                    suffix={suffixForm}
                    onSearch={onSearch}
                    placeholder={placeholder}
                    onChange={showAutoSearch ? searchChange : undefined}
                  />
                </div>
              )}
              <Table
                query={handleQuerySet ? handleQuerySet(handleQuery) : handleQuery}
                rowSelectionType={rowSelectionType || DEFAULT_ROWSELECTIONTYPE}
                ref={tableRef}
                columns={curModel.columns}
                url={curModel.url}
                handleResult={handleResult}
                treeStructure={treeStructure}
                treeId={treeId}
                treeParentId={treeParentId}
              />
            </>
          }

        </Skeleton>
      </Modal>
    );
  }
);
